using System;
using System.Collections.Generic;
using System.Text;
using CLELCore.Assembly;
using CLELCore.Assembly.StreamTables;
using CLELCore.Assembly.StreamTables.StreamTableRows;
using CLELCore.Assembly.BlobStreams;
using CLELCore.Assembly.Debug;
using CLELCore.Assembly.Debug.DebugInformation;
using CLELCore.Executable;

namespace CLELCore.Assembly.Generator.ValidAssemblyGenerator
{
	public class CLELValidAssemblyTextGenerator
	{
		private CLELAssembly _asm;
		private byte[] _buffer;
		private bool _little_endian;
		private CLELLogger _log;
		private int _rva;
		private AssemblyTextSection _text;
		private int _blob_size;
		private int _strings_size;
		private int _guid_size;

		public CLELValidAssemblyTextGenerator(CLELAssembly asm,byte[] buffer,
			bool little_endian,CLELLogger log,int rva)
		{
			_asm = asm;
			_text = (AssemblyTextSection)_asm.TextSection;
			_buffer = buffer;
			_little_endian = little_endian;
			_log = log;
			_rva = rva;
		}

		public void WriteTextSection()
		{
			WriteEntryPoint();
			WriteCLIHeader();
			WriteStrongNameSignature();
			WriteImportTable();
			WriteImportAddressTable();
			WriteImportLookupTable();
			WriteNameTable();
			int next_rva = WriteMetadataRoot();
			WriteStreamHeaders(next_rva);
			WriteStringStream();
			WriteGUIDStream();
			WriteBlobStream();
			WriteUSStream();
			WriteTildaStream();
			WriteMethodHeaders();
			WriteCLIResources();
			WriteDebug();
		}

		private void WriteEntryPoint()
		{
			int entry_point_offset = _asm.StandardFields.AddressOfEntryPoint - _rva;

			if(entry_point_offset < 0 || entry_point_offset+EntryPointRVA.ENTRYPOINTRVA_SIZE >= _buffer.Length)
			{
				_log.WriteLine("Error entry point offset out of bounds: " + entry_point_offset);
				throw new CLELWriterException("Error entry point offset out of bounds: "+ entry_point_offset);
			}

			EntryPointRVA entry_point_rva = _text.EntryPointRVA;
			Bits.SetShort(entry_point_offset,_buffer,entry_point_rva.Magic,_little_endian);
			Bits.SetInt(entry_point_offset+2,_buffer,entry_point_rva.RVA,_little_endian);
		}

		private void WriteCLIHeader()
		{
			DataDirectory cliheader_dd = _asm.DataDirectories[DataDirectories.CLIHEADER_INDEX];
			int cliheader_offset = cliheader_dd.VirtualAddress - _rva;

			if(cliheader_offset < 0 || cliheader_offset+CLIHeader.CLIHEADER_SIZE >= _buffer.Length)
			{
				_log.WriteLine("Error cli header offset out of bounds: " + cliheader_offset);
				throw new CLELWriterException("Error cli header offset out of bounds: "+ cliheader_offset);
			}
			
			CLIHeader cli_header = _text.CLIHeader;

			Bits.SetInt(cliheader_offset,_buffer,cli_header.Cb,_little_endian);
			Bits.SetShort(cliheader_offset+4,_buffer,cli_header.MajorRuntimeVersion,_little_endian);
			Bits.SetShort(cliheader_offset+6,_buffer,cli_header.MinorRuntimeVersion,_little_endian);
			DataDirectory dd = cli_header.Metadata;
			Bits.SetInt(cliheader_offset+8,_buffer,dd.VirtualAddress,_little_endian);
			Bits.SetInt(cliheader_offset+12,_buffer,dd.Size,_little_endian);
			Bits.SetInt(cliheader_offset+16,_buffer,cli_header.Flags,_little_endian);
			Bits.SetInt(cliheader_offset+20,_buffer,cli_header.EntryPointToken.GetEncodedToken(),_little_endian);
			
			dd = cli_header.Resources;
			Bits.SetInt(cliheader_offset+24,_buffer,dd.VirtualAddress,_little_endian);
			Bits.SetInt(cliheader_offset+28,_buffer,dd.Size,_little_endian);

			dd = cli_header.StrongNameSignature;
			Bits.SetInt(cliheader_offset+32,_buffer,dd.VirtualAddress,_little_endian);
			Bits.SetInt(cliheader_offset+36,_buffer,dd.Size,_little_endian);
			
			Bits.SetLong(cliheader_offset+40,_buffer,cli_header.CodeManagerTable,_little_endian);
			Bits.SetLong(cliheader_offset+48,_buffer,cli_header.VTableFixups,_little_endian);
			Bits.SetLong(cliheader_offset+56,_buffer,cli_header.ExportAddressTableJumps,_little_endian);
			Bits.SetLong(cliheader_offset+64,_buffer,cli_header.ManageNativeHeader,_little_endian);
		}

		private void WriteStrongNameSignature()
		{
			DataDirectory strong_dd = _text.CLIHeader.StrongNameSignature;
			int strong_offset = strong_dd.VirtualAddress;
			if(strong_offset != 0)
			{
				strong_offset -= _rva;
				int size = strong_dd.Size;

				if(strong_offset < 0 || size <= 0 || strong_offset+size >= _buffer.Length)
				{
					_log.WriteLine("Error strong name signature offset out of bounds: " + strong_offset);
					throw new CLELParserException("Error strong name signature offset out of bounds: "+ strong_offset);
				}

				Bits.SetBytes(strong_offset,_buffer,_text.StrongNameSignature);
			}
		}

		private void WriteImportTable()
		{
			DataDirectory import_dd = _asm.DataDirectories[DataDirectories.IMPORTTABLE_INDEX];
			int import_offset = import_dd.VirtualAddress - _rva;

			if(import_offset < 0 || import_offset+ImportTable.IMPORTTABLE_SIZE >= _buffer.Length)
			{
				_log.WriteLine("Error import table offset out of bounds: " + import_offset);
				throw new CLELWriterException("Error import table offset out of bounds: "+ import_offset);
			}

			ImportTable import_table = _text.ImportTable;

			Bits.SetInt(import_offset,_buffer,import_table.ImportLookupTable,_little_endian);
			Bits.SetInt(import_offset+4,_buffer,import_table.DateTimeStamp,_little_endian);
			Bits.SetInt(import_offset+8,_buffer,import_table.ForwarderChain,_little_endian);
			Bits.SetInt(import_offset+12,_buffer,import_table.Name,_little_endian);
			Bits.SetInt(import_offset+16,_buffer,import_table.ImportAddressTable,_little_endian);
			Bits.SetBytes(import_offset+20,_buffer,import_table.Padding);
		}
		
		private void WriteImportAddressTable()
		{
			DataDirectory importaddress_dd = _asm.DataDirectories[DataDirectories.IMPORTADDRESSTABLE_INDEX];
			int importaddress_offset = importaddress_dd.VirtualAddress - _rva;

			if(importaddress_offset < 0 || importaddress_offset+ImportAddressTable.IMPORTADDRESSTABLE_SIZE >= _buffer.Length)
			{
				_log.WriteLine("Error import address table offset out of bounds: " + importaddress_offset);
				throw new CLELWriterException("Error import address table offset out of bounds: "+ importaddress_offset);
			}

			ImportAddressTable import_address_table = _text.ImportAddressTable;

			Bits.SetInt(importaddress_offset,_buffer,import_address_table.NameTableRVA,_little_endian);
			Bits.SetBytes(importaddress_offset+4,_buffer,import_address_table.Padding);
		}

		private void WriteImportLookupTable()
		{
			int importlookup_offset = _text.ImportTable.ImportLookupTable - _rva;

			if(importlookup_offset < 0 || importlookup_offset+ImportLookupTable.IMPORTLOOKUPTABLE_SIZE >= _buffer.Length)
			{
				_log.WriteLine("Error import lookup table offset out of bounds: " + importlookup_offset);
				throw new CLELWriterException("Error import lookup table offset out of bounds: "+ importlookup_offset);
			}

			ImportLookupTable import_lookup_table = _text.ImportLookupTable;
			
			Bits.SetInt(importlookup_offset,_buffer,import_lookup_table.NameTableRVA,_little_endian);
			//Bits.SetBytes(importlookup_offset+4,_buffer,import_lookup_table.Padding);
			//Bits.SetBytes(importlookup_offset+4+import_lookup_table.Padding.Length,_buffer,import_lookup_table.Undocumented);
		}

		private void WriteNameTable()
		{
			int name_offset = _text.ImportAddressTable.NameTableRVA - _rva;;

			if(name_offset < 0 || name_offset+NameTable.NAMETABLE_SIZE >= _buffer.Length)
			{
				_log.WriteLine("Error name table offset out of bounds: " + name_offset);
				throw new CLELWriterException("Error name table offset out of bounds: "+ name_offset);
			}

			NameTable name_table = _text.NameTable;

			Bits.SetShort(name_offset,_buffer,name_table.Hint,_little_endian);
			Bits.SetBytes(name_offset+2,_buffer,name_table.Name1);
			Bits.SetBytes(name_offset+2+name_table.Name1.Length,_buffer,name_table.Name2);
			Bits.SetBytes(name_offset+2+name_table.Name1.Length+name_table.Name2.Length,_buffer,name_table.Undocumented);
		}

		private int WriteMetadataRoot()
		{
			DataDirectory metadata_dd = _text.CLIHeader.Metadata;
			int metadata_offset = metadata_dd.VirtualAddress - _rva;
			int metadata_size = metadata_dd.Size;

			if(metadata_offset < 0 || metadata_offset+metadata_size >= _buffer.Length)
			{
				_log.WriteLine("Error metadata offset out of bounds: " + metadata_offset);
				throw new CLELWriterException("Error metadata offset out of bounds: "+ metadata_offset);
			}

			MetadataRoot metadata = _text.MetadataRoot;

			Bits.SetInt(metadata_offset,_buffer,metadata.Signature,_little_endian);
			Bits.SetShort(metadata_offset+4,_buffer,metadata.MajorVersion,_little_endian);
			Bits.SetShort(metadata_offset+6,_buffer,metadata.MinorVersion,_little_endian);
			Bits.SetInt(metadata_offset+8,_buffer,metadata.Reserved,_little_endian);
			Bits.SetInt(metadata_offset+12,_buffer,metadata.VersionLength,_little_endian);
			Bits.SetBytes(metadata_offset+16,_buffer,metadata.Version);
			Bits.SetShort(metadata_offset+16+metadata.Version.Length,_buffer,metadata.Flags,_little_endian);
			Bits.SetShort(metadata_offset+18+metadata.Version.Length,_buffer,metadata.Streams,_little_endian);

			return metadata_offset+20+metadata.Version.Length;
		}
		
		private void WriteStreamHeaders(int next_rva)
		{
			int num_streams = _text.MetadataRoot.Streams;
			if(num_streams < 0)
			{
				_log.WriteLine("Error number of streams out of bounds: " + num_streams);
				throw new CLELWriterException("Error number of streams out of bounds: "+ num_streams);
			}

			StreamHeaders headers = _text.StreamHeaders;
			StreamHeader sh;
			int i;
			int next = next_rva;
			for(i = 0;i < num_streams;i++)
			{
				sh = headers[i];

				Bits.SetInt(next,_buffer,sh.Offset,_little_endian);
				Bits.SetInt(next+4,_buffer,sh.Size,_little_endian);
				Bits.SetBytes(next+8,_buffer,sh.Name);
				next += (8+sh.Name.Length);
			}
		}
		
		private void WriteStringStream()
		{
			DataDirectory metadata_dd = _text.CLIHeader.Metadata;
			int metadata_offset = metadata_dd.VirtualAddress;

			StreamHeader strings_sh = _text.StreamHeaders.GetStreamHeader(StreamHeader.STRINGS_NAME);
			if(strings_sh == null)
				return;
			int off = metadata_offset-_rva+strings_sh.Offset;
			int size = strings_sh.Size;
			if(off < 0 || off+size >= _buffer.Length)
			{
				_log.WriteLine("Error strings stream out of bounds: " + off);
				throw new CLELWriterException("Error strings stream out of bounds: "+ off);
			}

			StringsStream strings = _text.StringsStream;

			int i;
			int next = off;
			byte [] bytes;
			for(i = 0;i < size;)
			{
				bytes = strings.Get(i);
				if(bytes != null)
				{
					Bits.SetBytes(next,_buffer,bytes);
					i += bytes.Length;
					next += bytes.Length;
				}
			}
		}
		
		private void WriteGUIDStream()
		{
			DataDirectory metadata_dd = _text.CLIHeader.Metadata;
			int metadata_offset = metadata_dd.VirtualAddress;

			StreamHeader guid_sh = _text.StreamHeaders.GetStreamHeader(StreamHeader.GUID_NAME);
			if(guid_sh == null)
				return;
			int off = metadata_offset-_rva+guid_sh.Offset;
			int size = guid_sh.Size;
			if(off < 0 || off+size >= _buffer.Length)
			{
				_log.WriteLine("Error guid stream out of bounds: " + off);
				throw new CLELWriterException("Error guid stream out of bounds: "+ off);
			}

			GUIDStream guids = _text.GUIDStream;
			
			int i;
			int guid_size = GUID.GUID_SIZE;
			byte [] guid;
			for(i = 0;i < size;i += guid_size)
			{
				guid = guids.Get(i);
				Bits.SetBytes(off+i,_buffer,guid);
			}
		}
		
		private void WriteBlobStream()
		{
			DataDirectory metadata_dd = _text.CLIHeader.Metadata;
			int metadata_offset = metadata_dd.VirtualAddress;

			StreamHeader blob_sh = _text.StreamHeaders.GetStreamHeader(StreamHeader.BLOB_NAME);
			if(blob_sh == null)
				return;
			int off = metadata_offset-_rva+blob_sh.Offset;
			int size = blob_sh.Size;
			if(off < 0 || off+size >= _buffer.Length)
			{
				_log.WriteLine("Error blob stream out of bounds: " + off);
				throw new CLELWriterException("Error blob stream out of bounds: "+ off);
			}

			BlobStream blobs = _text.BlobStream;
		
			byte [] blob;
			int i = 0;
			while(i < size)
			{
				blob = blobs.GetBytes(i);
				Bits.SetBytes(off+i,_buffer,blob);
				/*
				Console.Write(i.ToString("X")+ ": ");
				for(int k = 0;k < blob.Length;k++)
					Console.Write(blob[k].ToString("X")+ " ");
				Console.WriteLine();
				*/
				i += blob.Length;
			}
		}

		private void WriteUSStream()
		{
			DataDirectory metadata_dd = _text.CLIHeader.Metadata;
			int metadata_offset = metadata_dd.VirtualAddress;

			StreamHeader us_sh = _text.StreamHeaders.GetStreamHeader(StreamHeader.US_NAME);
			if(us_sh == null)
				return;
			int off = metadata_offset-_rva+us_sh.Offset;
			int size = us_sh.Size;
			if(off < 0 || off+size >= _buffer.Length)
			{
				_log.WriteLine("Error us stream out of bounds: " + off);
				throw new CLELWriterException("Error us stream out of bounds: "+ off);
			}

			USStream us = _text.USStream;

			/*
			int next = off;
			byte [] bytes;
			int stop = off+size;
			int i = 0;
			while(next < stop)
			{
				bytes = us.Get(i);
				if(bytes != null)
				{
					Bits.SetShort(next,_buffer,(short)bytes.Length,false);
				}
				next += 2;
				if(bytes != null)
				{
					Bits.SetBytes(next,_buffer,bytes);
					i += bytes.Length;
					next += bytes.Length;	
				}
			}
			*/
			byte [] bytes;
			int i = 0;
			while(i < size)
			{
				bytes = us.Get(i);
				Bits.SetBytes(off+i,_buffer,bytes);
				i += bytes.Length;
			}
		}
		
		private void WriteTildaStream()
		{
			DataDirectory metadata_dd = _text.CLIHeader.Metadata;
			int metadata_offset = metadata_dd.VirtualAddress;

			StreamHeader tilda_sh = _text.StreamHeaders.GetStreamHeader(StreamHeader.TILDA_NAME);
			if(tilda_sh == null)
				return;
			int tilda_offset = metadata_offset-_rva+tilda_sh.Offset;
			int tilda_size = tilda_sh.Size;
			if(tilda_offset < 0 || tilda_offset+tilda_size >= _buffer.Length)
			{
				_log.WriteLine("Error pound tilda stream out of bounds: " + tilda_offset);
				throw new CLELWriterException("Error pound tilda stream out of bounds: "+ tilda_offset);
			}

			PoundTildaStream tilda = _text.PoundTildaStream;
			
			Bits.SetInt(tilda_offset,_buffer,tilda.Reserved,_little_endian);
			
			byte[] temp = new byte[4];
			temp[0] = tilda.MajorVersion;
			temp[1] = tilda.MinorVersion;
			temp[2] = tilda.HeapSizes;
			temp[3] = tilda.Reserved2;
			Bits.SetBytes(tilda_offset+4,_buffer,temp);
			
			Bits.SetLong(tilda_offset+8,_buffer,tilda.Valid,_little_endian);
			Bits.SetLong(tilda_offset+16,_buffer,tilda.Sorted,_little_endian);
			
			int[] num_rows = tilda.TableRows;
			int i;
			int next = tilda_offset+24;
			int stop = num_rows.Length;
			for(i = 0;i < stop;i++)
			{
				if(num_rows[i] > 0)
				{
					Bits.SetInt(next,_buffer,num_rows[i],_little_endian);
					next += 4;
				}
			}

			_blob_size = _text.BlobStream.Size;
			_strings_size = _text.StringsStream.Size;
			_guid_size = _text.GUIDStream.Size;
			
			StreamTable[] tables = tilda.Tables;
			for(i = 0;i < 64;i++)
			{
				if(num_rows[i] > 0)
				{
					next = SetStreamTable(i,tables[i],next,num_rows);
				}
			}
		}
	
		private int SetStreamTable(int type,StreamTable table,int off,int[] num_rows)
		{
			int ret = 0;
			switch(type)
			{
				case StreamTable.MODULE_TABLE: 
						ret = SetModuleTable((ModuleTable)table,off,num_rows);
						break;
				case StreamTable.TYPEREF_TABLE:
						ret = SetTypeRefTable((TypeRefTable)table,off,num_rows);
						break;
				case StreamTable.TYPEDEF_TABLE:
						ret = SetTypeDefTable((TypeDefTable)table,off,num_rows);
						break;
				case StreamTable.METHODDEF_TABLE:
						ret = SetMethodDefTable((MethodDefTable)table,off,num_rows);
						break;
				case StreamTable.PARAM_TABLE:
						ret = SetParamTable((ParamTable)table,off,num_rows);
						break;
				case StreamTable.MEMBERREF_TABLE:
						ret = SetMemberRefTable((MemberRefTable)table,off,num_rows);
						break;
				case StreamTable.STANDALONESIG_TABLE:
						ret = SetStandAloneSigTable((StandAloneSigTable)table,off,num_rows);
						break;
				case StreamTable.ASSEMBLY_TABLE:
						ret = SetAssemblyTable((AssemblyTable)table,off,num_rows);
						break;
				case StreamTable.ASSEMBLYREF_TABLE:
						ret = SetAssemblyRefTable((AssemblyRefTable)table,off,num_rows);
						break;
				case StreamTable.ASSEMBLYOS_TABLE:
						ret = SetAssemblyOSTable((AssemblyOSTable)table,off,num_rows);
						break;
				case StreamTable.ASSEMBLYPROCESSOR_TABLE:
						ret = SetAssemblyProcessorTable((AssemblyProcessorTable)table,off,num_rows);
						break;
				case StreamTable.ASSEMBLYREFOS_TABLE:
						ret = SetAssemblyRefOSTable((AssemblyRefOSTable)table,off,num_rows);
						break;
				case StreamTable.ASSEMBLYREFPROCESSOR_TABLE:
						ret = SetAssemblyRefProcessorTable((AssemblyRefProcessorTable)table,off,num_rows);
						break;
				case StreamTable.CLASSLAYOUT_TABLE:
						ret = SetClassLayoutTable((ClassLayoutTable)table,off,num_rows);
						break;
				case StreamTable.CONSTANT_TABLE:
						ret = SetConstantTable((ConstantTable)table,off,num_rows);
						break;
				case StreamTable.CUSTUMATTRIBUTE_TABLE:
						ret = SetCustumAttributeTable((CustumAttributeTable)table,off,num_rows);
						break;
				case StreamTable.DECLSECURITY_TABLE:
						ret = SetDeclSecurityTable((DeclSecurityTable)table,off,num_rows);
						break;
				case StreamTable.EVENTMAP_TABLE:
						ret = SetEventMapTable((EventMapTable)table,off,num_rows);
						break;
				case StreamTable.EVENT_TABLE:
						ret = SetEventTable((EventTable)table,off,num_rows);
						break;
				case StreamTable.EXPORTEDTYPE_TABLE:
						ret = SetExportedTypeTable((ExportedTypeTable)table,off,num_rows);
						break;
				case StreamTable.FIELD_TABLE:
						ret = SetFieldTable((FieldTable)table,off,num_rows);
						break;
				case StreamTable.FIELDLAYOUT_TABLE:
						ret = SetFieldLayoutTable((FieldLayoutTable)table,off,num_rows);
						break;
				case StreamTable.FIELDMARSHAL_TABLE:
						ret = SetFieldMarshalTable((FieldMarshalTable)table,off,num_rows);
						break;
				case StreamTable.FIELDRVA_TABLE:
						ret = SetFieldRVATable((FieldRVATable)table,off,num_rows);
						break;
				case StreamTable.FILE_TABLE:
						ret = SetFileTable((FileTable)table,off,num_rows);
						break;
				case StreamTable.IMPLMAP_TABLE:
						ret = SetImplMapTable((ImplMapTable)table,off,num_rows);
						break;
				case StreamTable.INTERFACEIMPL_TABLE:
						ret = SetInterfaceImplTable((InterfaceImplTable)table,off,num_rows);
						break;
				case StreamTable.MANIFESTRESOURCE_TABLE:
						ret = SetManifestResourceTable((ManifestResourceTable)table,off,num_rows);
						break;
				case StreamTable.METHODIMPL_TABLE:
						ret = SetMethodImplTable((MethodImplTable)table,off,num_rows);
						break;
				case StreamTable.METHODSEMANTICS_TABLE:
						ret = SetMethodSemanticsTable((MethodSemanticsTable)table,off,num_rows);
						break;
				case StreamTable.MODULEREF_TABLE:
						ret = SetModuleRefTable((ModuleRefTable)table,off,num_rows);
						break;
				case StreamTable.NESTEDCLASS_TABLE:
						ret = SetNestedClassTable((NestedClassTable)table,off,num_rows);
						break;
				case StreamTable.PROPERTY_TABLE:
						ret = SetPropertyTable((PropertyTable)table,off,num_rows);
						break;
				case StreamTable.PROPERTYMAP_TABLE:
						ret = SetPropertyMapTable((PropertyMapTable)table,off,num_rows);
						break;
				case StreamTable.TYPESPEC_TABLE:
						ret = SetTypeSpecTable((TypeSpecTable)table,off,num_rows);
						break;
				case StreamTable.METHODSPEC_TABLE:
						ret = SetMethodSpecTable((MethodSpecTable)table,off,num_rows);
						break;
				case StreamTable.GENERICPARAM_TABLE:
						ret = SetGenericParamTable((GenericParamTable)table,off,num_rows);
						break;
				case StreamTable.GENERICPARAMCONSTRAINT_TABLE:
						ret = SetGenericParamConstraintTable((GenericParamConstraintTable)table,off,num_rows);
						break;
				default:
						_log.WriteLine("Error unknown stream table: " + type);
						throw new CLELWriterException("Error unknown stream table: "+ type);
			}
			return ret;
		}

		private int SetGenericParamConstraintTable(GenericParamConstraintTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			GenericParamConstraintTableRow row;
			int stop = table.Count;
			int genericparam_rows = num_rows[StreamTable.GENERICPARAM_TABLE];
			byte[] constraint;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				if(genericparam_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Owner,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Owner,_little_endian);
					next += 4;
				}
				constraint = TokenCompressor.CompressTypeDefOrRefToken(num_rows,row.Constraint);
				Bits.SetBytes(next,_buffer,constraint);
				next += constraint.Length;
			}
			return next;
		}

		private int SetGenericParamTable(GenericParamTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			GenericParamTableRow row;
			int stop = table.Count;
			byte[] owner;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				
				Bits.SetShort(next,_buffer,row.Number,_little_endian);
				Bits.SetShort(next+2,_buffer,row.Flags,_little_endian);
				next += 4;
				
				owner = TokenCompressor.CompressTypeOrMethodDefToken(num_rows,row.Owner);
				Bits.SetBytes(next,_buffer,owner);
				next += owner.Length;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetMethodSpecTable(MethodSpecTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			MethodSpecTableRow row;
			int stop = table.Count;
			byte[] method;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				
				method = TokenCompressor.CompressMethodDefOrRefToken(num_rows,row.Method);
				Bits.SetBytes(next,_buffer,method);
				next += method.Length;
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Instantiation,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Instantiation,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetTypeSpecTable(TypeSpecTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			TypeSpecTableRow row;
			int stop = table.Count;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Signature,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Signature,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetPropertyMapTable(PropertyMapTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			PropertyMapTableRow row;
			int stop = table.Count;
			int typedef_rows = num_rows[StreamTable.TYPEDEF_TABLE];
			int property_rows = num_rows[StreamTable.PROPERTY_TABLE];
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				if(typedef_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Parent,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Parent,_little_endian);
					next += 4;
				}
				if(property_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.PropertyList,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.PropertyList,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetPropertyTable(PropertyTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			PropertyTableRow row;
			int stop = table.Count;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetShort(next,_buffer,row.Flags,_little_endian);
				next += 2;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					next += 4;
				}
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Type,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Type,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetNestedClassTable(NestedClassTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			NestedClassTableRow row;
			int stop = table.Count;
			int typedef_rows = num_rows[StreamTable.TYPEDEF_TABLE];
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				if(typedef_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.NestedClass,_little_endian);
					Bits.SetShort(next+2,_buffer,(short)row.EnclosingClass,_little_endian);
					next += 4;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.NestedClass,_little_endian);
					Bits.SetInt(next+4,_buffer,row.EnclosingClass,_little_endian);
					next += 8;
				}
			}
			return next;
		}

		private int SetModuleRefTable(ModuleRefTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			ModuleRefTableRow row;
			int stop = table.Count;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetMethodSemanticsTable(MethodSemanticsTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			MethodSemanticsTableRow row;
			int stop = table.Count;
			int methoddef_rows = num_rows[StreamTable.METHODDEF_TABLE];
			byte[] association;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetShort(next,_buffer,row.Semantics,_little_endian);
				next += 2;
				if(methoddef_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Method,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Method,_little_endian);
					next += 4;
				}
				association = TokenCompressor.CompressHasSemanticsToken(num_rows,row.Association);
				Bits.SetBytes(next,_buffer,association);
				next += association.Length;
			}
			return next;
		}

		private int SetMethodImplTable(MethodImplTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			MethodImplTableRow row;
			int stop = table.Count;
			int typedef_rows = num_rows[StreamTable.TYPEDEF_TABLE];
			byte[] method_body;
			byte[] method_declaration;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				if(typedef_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Class,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Class,_little_endian);
					next += 4;
				}
				
				method_body = TokenCompressor.CompressMethodDefOrRefToken(num_rows,row.MethodBody);
				Bits.SetBytes(next,_buffer,method_body);
				next += method_body.Length;
				
				method_declaration = TokenCompressor.CompressMethodDefOrRefToken(num_rows,row.MethodDeclaration);
				Bits.SetBytes(next,_buffer,method_declaration);
				next += method_declaration.Length;
			}
			return next;
		}

		private int SetManifestResourceTable(ManifestResourceTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			ManifestResourceTableRow row;
			int stop = table.Count;
			byte[] implementation;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.Offset,_little_endian);
				Bits.SetInt(next+4,_buffer,row.Flags,_little_endian);
				next += 8;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					next += 4;
				}
				implementation = TokenCompressor.CompressImplementationToken(num_rows,row.Implementation);
				Bits.SetBytes(next,_buffer,implementation);
				next += implementation.Length;
			}
			return next;
		}

		private int SetInterfaceImplTable(InterfaceImplTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			InterfaceImplTableRow row;
			int stop = table.Count;
			int typedef_rows = num_rows[StreamTable.TYPEDEF_TABLE];
			byte[] interfaces;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				if(typedef_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Class,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Class,_little_endian);
					next += 4;
				}
				interfaces = TokenCompressor.CompressTypeDefOrRefToken(num_rows,row.Interface);
				Bits.SetBytes(next,_buffer,interfaces);
				next += interfaces.Length;
			}
			return next;
		}

		private int SetImplMapTable(ImplMapTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			ImplMapTableRow row;
			int stop = table.Count;
			int moduleref_rows = num_rows[StreamTable.MODULEREF_TABLE];	
			byte[] member_forwarded;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);

				Bits.SetShort(next,_buffer,row.MappingFlags,_little_endian);
				next += 2;				

				member_forwarded = TokenCompressor.CompressTypeDefOrRefToken(num_rows,row.MemberForwarded);
				Bits.SetBytes(next,_buffer,member_forwarded);
				next += member_forwarded.Length;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.ImportName,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.ImportName,_little_endian);
					next += 4;
				}
				if(moduleref_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.ImportScope,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.ImportScope,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetFileTable(FileTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			FileTableRow row;
			int stop = table.Count;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.Flags,_little_endian);
				next += 4;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					next += 4;
				}
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.HashValue,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.HashValue,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetFieldRVATable(FieldRVATable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			FieldRVATableRow row;
			int stop = table.Count;
			int field_rows = num_rows[StreamTable.FIELD_TABLE];	
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.RVA,_little_endian);
				next += 4;
				if(field_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Field,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Field,_little_endian);
					next += 4;
				}

				//not in stream table - field default value
				Bits.SetBytes(row.RVA-_rva,_buffer,row.DefaultValue);
			}
			return next;
		}

		private int SetFieldMarshalTable(FieldMarshalTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			FieldMarshalTableRow row;
			int stop = table.Count;
			byte[] parent;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);

				parent = TokenCompressor.CompressHasFieldMarshallToken(num_rows,row.Parent);
				Bits.SetBytes(next,_buffer,parent);
				next += parent.Length;
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.NativeType,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.NativeType,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetFieldLayoutTable(FieldLayoutTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			FieldLayoutTableRow row;
			int stop = table.Count;
			int field_rows = num_rows[StreamTable.FIELD_TABLE];	
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.Offset,_little_endian);
				next += 4;
				if(field_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Field,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Field,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetFieldTable(FieldTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			FieldTableRow row;
			int stop = table.Count;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetShort(next,_buffer,row.Flags,_little_endian);
				next += 2;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					next += 4;
				}
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Signature,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Signature,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetExportedTypeTable(ExportedTypeTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			ExportedTypeTableRow row;
			int stop = table.Count;
			byte[] implementation;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.Flags,_little_endian);
				next += 4;
				Bits.SetInt(next,_buffer,row.TypeDefId,_little_endian);
				next += 4;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.TypeName,_little_endian);
					Bits.SetShort(next+2,_buffer,(short)row.TypeNamespace,_little_endian);
					next += 4;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.TypeName,_little_endian);
					Bits.SetInt(next+4,_buffer,row.TypeNamespace,_little_endian);
					next += 8;
				}
				implementation = TokenCompressor.CompressImplementationToken(num_rows,row.Implementation);
				Bits.SetBytes(next,_buffer,implementation);
				next += implementation.Length;
			}
			return next;
		}

		private int SetEventTable(EventTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			EventTableRow row;
			int stop = table.Count;
			byte[] event_type;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetShort(next,_buffer,row.EventFlags,_little_endian);
				next += 2;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					next += 4;
				}
				event_type = TokenCompressor.CompressTypeDefOrRefToken(num_rows,row.EventType);
				Bits.SetBytes(next,_buffer,event_type);
				next += event_type.Length;
			}
			return next;
		}

		private int SetEventMapTable(EventMapTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			EventMapTableRow row;
			int stop = table.Count;
			int typedef_rows = num_rows[StreamTable.TYPEDEF_TABLE];
			int event_rows = num_rows[StreamTable.EVENT_TABLE];
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				if(typedef_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Parent,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Parent,_little_endian);
					next += 4;
				}
				if(event_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Event,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Event,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetDeclSecurityTable(DeclSecurityTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			DeclSecurityTableRow row;
			int stop = table.Count;
			byte[] parent;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				
				Bits.SetShort(next,_buffer,row.Action,_little_endian);
				next += 2;
				parent = TokenCompressor.CompressHasDeclSecurityToken(num_rows,row.Parent);
				Bits.SetBytes(next,_buffer,parent);
				next += parent.Length;
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.PermissionSet,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.PermissionSet,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetCustumAttributeTable(CustumAttributeTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			CustumAttributeTableRow row;
			int stop = table.Count;
			byte[] parent,type;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				
				parent = TokenCompressor.CompressHasCustomAttributeToken(num_rows,row.Parent);
				Bits.SetBytes(next,_buffer,parent);
				next += parent.Length;
				
				type = TokenCompressor.CompressCustomAttributeTypeToken(num_rows,row.CustomAttributeType);
				Bits.SetBytes(next,_buffer,type);
				next += type.Length;
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Value,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Value,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetConstantTable(ConstantTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			ConstantTableRow row;
			int stop = table.Count;
			byte [] parent;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				
				Bits.SetShort(next,_buffer,row.ConstantType,_little_endian);
				next += 2;
				
				parent = TokenCompressor.CompressHasConstantToken(num_rows,row.Parent);
				Bits.SetBytes(next,_buffer,parent);
				next += parent.Length;
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Value,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Value,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetClassLayoutTable(ClassLayoutTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			ClassLayoutTableRow row;
			int stop = table.Count;
			int typedef_rows = num_rows[StreamTable.TYPEDEF_TABLE];
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetShort(next,_buffer,row.PackingSize,_little_endian);
				Bits.SetInt(next+2,_buffer,row.ClassSize,_little_endian);
				next += 6;
				if(typedef_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Parent,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Parent,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetAssemblyRefProcessorTable(AssemblyRefProcessorTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			AssemblyRefProcessorTableRow row;
			int stop = table.Count;
			int assemblyref_rows = num_rows[StreamTable.ASSEMBLYREF_TABLE];
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.Processor,_little_endian);
				next += 4;
				if(assemblyref_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.AssemblyRef,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.AssemblyRef,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetAssemblyRefOSTable(AssemblyRefOSTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			AssemblyRefOSTableRow row;
			int stop = table.Count;
			int assemblyref_rows = num_rows[StreamTable.ASSEMBLYREF_TABLE];
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.OSPlatformId,_little_endian);
				Bits.SetInt(next+4,_buffer,row.OSMajorVersion,_little_endian);
				Bits.SetInt(next+8,_buffer,row.OSMinorVersion,_little_endian);
				next += 12;
				if(assemblyref_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.AssemblyRef,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.AssemblyRef,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetAssemblyProcessorTable(AssemblyProcessorTable table,int off,int[] num_rows)
		{
			int next = off;
			AssemblyProcessorTableRow row;
			int stop = table.Count;
			int i;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.Processor,_little_endian);
				next += 4;
			}
			return next;
		}

		private int SetAssemblyOSTable(AssemblyOSTable table,int off,int[] num_rows)
		{
			int next = off;
			AssemblyOSTableRow row;
			int stop = table.Count;
			int i;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.OSPlatformId,_little_endian);
				Bits.SetInt(next+4,_buffer,row.OSMajorVersion,_little_endian);
				Bits.SetInt(next+8,_buffer,row.OSMinorVersion,_little_endian);
				next += 12;
			}
			return next;
		}

		private int SetAssemblyRefTable(AssemblyRefTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			AssemblyRefTableRow row;
			int stop = table.Count;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetShort(next,_buffer,row.MajorVersion,_little_endian);
				Bits.SetShort(next+2,_buffer,row.MinorVersion,_little_endian);
				Bits.SetShort(next+4,_buffer,row.BuildNumber,_little_endian);
				Bits.SetShort(next+6,_buffer,row.RevisionNumber,_little_endian);
				Bits.SetInt(next+8,_buffer,row.Flags,_little_endian);
				next += 12;
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.PublicKeyOrToken,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.PublicKeyOrToken,_little_endian);
					next += 4;
				}
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					Bits.SetShort(next+2,_buffer,(short)row.Culture,_little_endian);
					next += 4;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					Bits.SetInt(next+4,_buffer,row.Culture,_little_endian);
					next += 8;
				}
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.HashValue,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.HashValue,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetAssemblyTable(AssemblyTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			AssemblyTableRow row;
			int stop = table.Count;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.HashAlgId,_little_endian);
				Bits.SetShort(next+4,_buffer,row.MajorVersion,_little_endian);
				Bits.SetShort(next+6,_buffer,row.MinorVersion,_little_endian);
				Bits.SetShort(next+8,_buffer,row.BuildNumber,_little_endian);
				Bits.SetShort(next+10,_buffer,row.RevisionNumber,_little_endian);
				Bits.SetInt(next+12,_buffer,row.Flags,_little_endian);
				next += 16;
				if(_blob_size <  0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.PublicKey,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.PublicKey,_little_endian);
					next += 4;
				}
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					Bits.SetShort(next+2,_buffer,(short)row.Culture,_little_endian);
					next += 4;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					Bits.SetInt(next+4,_buffer,row.Culture,_little_endian);
					next += 8;
				}
			}
			return next;
		}

		private int SetStandAloneSigTable(StandAloneSigTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			StandAloneSigTableRow row;
			int stop = table.Count;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Signature,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Signature,_little_endian);
					next += 4;
				}
			}
		
			return next;
		}

		private int SetMemberRefTable(MemberRefTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			MemberRefTableRow row;
			int stop = table.Count;
			byte[] classes;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				
				classes = TokenCompressor.CompressMemberRefParentToken(num_rows,row.Class);
				Bits.SetBytes(next,_buffer,classes);
				next += classes.Length;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					next += 4;
				}
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Signature,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Signature,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetParamTable(ParamTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			ParamTableRow row;
			int stop = table.Count;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				
				Bits.SetShort(next,_buffer,row.Flags,_little_endian);
				Bits.SetShort(next+2,_buffer,row.Sequence,_little_endian);
				next += 4;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					next += 4;
				}
			}

			return next;
		}

		private int SetMethodDefTable(MethodDefTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			MethodDefTableRow row;
			int stop = table.Count;
			int param_rows = num_rows[StreamTable.PARAM_TABLE];
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				Bits.SetInt(next,_buffer,row.RVA,_little_endian);
				Bits.SetShort(next+4,_buffer,row.ImplFlags,_little_endian);
				Bits.SetShort(next+6,_buffer,row.Flags,_little_endian);
				next += 8;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					next += 4;
				}
				if(_blob_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Signature,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Signature,_little_endian);
					next += 4;
				}
				if(param_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.ParamList,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.ParamList,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetTypeRefTable(TypeRefTable table,int off,int[] num_rows)
		{
			int next = off;
			int i;
			int stop = table.Count;
			TypeRefTableRow row;
			byte[] resolution_scope;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);

				resolution_scope = TokenCompressor.CompressResolutionScopeToken(num_rows,row.ResolutionScope);
				Bits.SetBytes(next,_buffer,resolution_scope);
				next += resolution_scope.Length;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					Bits.SetShort(next+2,_buffer,(short)row.Namespace,_little_endian);
					next += 4;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					Bits.SetInt(next+4,_buffer,row.Namespace,_little_endian);
					next += 8;
				}
			}

			return next;
		}
		
		private int SetTypeDefTable(TypeDefTable table,int off,int[] num_rows)
		{
			int next = off;
			int stop = table.Count;
			TypeDefTableRow row;
			int i;
			int methoddef_rows = num_rows[StreamTable.METHODDEF_TABLE];
			int field_rows = num_rows[StreamTable.FIELD_TABLE];
			byte[] extends;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				
				Bits.SetInt(next,_buffer,row.Flags,_little_endian);
				next += 4;
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Name,_little_endian);
					Bits.SetShort(next+2,_buffer,(short)row.Namespace,_little_endian);
					next += 4;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Name,_little_endian);
					Bits.SetInt(next+4,_buffer,row.Namespace,_little_endian);
					next += 8;
				}
				extends = TokenCompressor.CompressTypeDefOrRefToken(num_rows,row.Extends);
				Bits.SetBytes(next,_buffer,extends);
				next += extends.Length;
				if(field_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.FieldList,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.FieldList,_little_endian);
					next += 4;
				}
				if(methoddef_rows < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.MethodList,_little_endian);
					next += 2;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.MethodList,_little_endian);
					next += 4;
				}
			}
			return next;
		}

		private int SetModuleTable(ModuleTable table,int off,int[] num_rows)
		{
			int next = off;
			int stop = table.Count;
			ModuleTableRow row;
			int i;
			for(i = 0;i < stop;i++)
			{
				row = table.Get(i);
				
				Bits.SetShort(next,_buffer,row.Generation,_little_endian);
				if(_strings_size < 0xffff)
				{
					Bits.SetShort(next+2,_buffer,(short)row.Name,_little_endian);
					next += 4;
				}
				else
				{
					Bits.SetInt(next+2,_buffer,row.Name,_little_endian);
					next += 6;
				}
				if(_guid_size < 0xffff)
				{
					Bits.SetShort(next,_buffer,(short)row.Mvid,_little_endian);
					Bits.SetShort(next+2,_buffer,(short)row.Encld,_little_endian);
					Bits.SetShort(next+4,_buffer,(short)row.EncBaseId,_little_endian);
					next += 6;
				}
				else
				{
					Bits.SetInt(next,_buffer,row.Mvid,_little_endian);
					Bits.SetInt(next+4,_buffer,row.Encld,_little_endian);
					Bits.SetInt(next+8,_buffer,row.EncBaseId,_little_endian);
					next += 12;
				}
			}
			return next;
		}
	
		private void WriteMethodHeaders()
		{
			List<MethodHeader> method_headers = _text.MethodHeaders;
			MethodDefTable md = (MethodDefTable)_text.PoundTildaStream.Tables[StreamTable.METHODDEF_TABLE];
			int i;
			int count = md.Count;
			MethodDefTableRow row;
			//int k = 0;
			for(i = 0;i < count;i++)
			{
				row = md.Get(i);
				if(row.RVA != 0)
				{
					//if(k > 6)
					//	return;
					//k++;
					SetMethodHeader(row.RVA-_rva,method_headers[i]);
				}
			}
		}

		private void SetMethodHeader(int off,MethodHeader mh)
		{
			if(mh != null)
			{
				byte[] bytes = mh.GetBytes(_little_endian);
				Bits.SetBytes(off,_buffer,bytes);
			}
		}

		private void WriteCLIResources()
		{
			DataDirectory res_dd = _text.CLIHeader.Resources;
			if(res_dd.VirtualAddress > 0)
			{
				int va = res_dd.VirtualAddress - _rva;
				List<CLIResource> resources = _text.CLIResources;
				if(resources != null)
				{
					int i;
					int stop = resources.Count;
					int res_size;
					int padding;
					byte [] res_data;
					for(i = 0;i < stop;i++)
					{
						res_data = resources[i].Data;
						if(res_data != null)
						{
							res_size = res_data.Length;
							Bits.SetInt(va,_buffer,res_size,_little_endian);
							va += 4;
							Bits.SetBytes(va,_buffer,res_data);
							va += res_size;
					
							padding = 8-((res_size+4)%8);
							if(padding == 8)
								padding = 0;
							va += padding;
						}
					}
				}
			}
		}

		private void WriteDebug()
		{
			DataDirectory debug_dd = _asm.DataDirectories[DataDirectories.DEBUG_INDEX];
			if(debug_dd.VirtualAddress > 0)
			{
				int debug_offset = debug_dd.VirtualAddress - _rva;
				DebugDirectory debug_image = _text.DebugDirectory;
				if(debug_image != null)
				{
					Bits.SetInt(debug_offset,_buffer,debug_image.Characteristics,_little_endian);
					Bits.SetInt(debug_offset+4,_buffer,debug_image.TimeDateStamp,_little_endian);
					Bits.SetShort(debug_offset+8,_buffer,debug_image.MajorVersion,_little_endian);
					Bits.SetShort(debug_offset+10,_buffer,debug_image.MinorVersion,_little_endian);
					Bits.SetInt(debug_offset+12,_buffer,debug_image.Type,_little_endian);
					Bits.SetInt(debug_offset+16,_buffer,debug_image.SizeOfData,_little_endian);
					Bits.SetInt(debug_offset+20,_buffer,debug_image.AddressOfRawData,_little_endian);
					Bits.SetInt(debug_offset+24,_buffer,debug_image.PointerToRawData,_little_endian);
				
					if(debug_image.Type == DebugDirectory.IMAGE_DEBUG_TYPE_CODEVIEW)
					{
						debug_offset = debug_image.AddressOfRawData-_rva;
						DebugCodeViewInfo cv = (DebugCodeViewInfo)debug_image.DebugInformation;

						Bits.SetInt(debug_offset,_buffer,cv.Signature,_little_endian);
						byte [] guid = cv.GUID.GUIDValue;
						Bits.SetBytes(debug_offset+4,_buffer,guid);
						Bits.SetInt(debug_offset+4+guid.Length,_buffer,cv.Age,_little_endian);
						Bits.SetBytes(debug_offset+8+guid.Length,_buffer,cv.Filename);
					}
				}
			}
		}
	}
}
